//-----------------------------------------------------------------------------
//
//Copyright(c) 2020, ThorsianWay Technologies Co, Ltd
//All rights reserved.
//
//IP Name       :   ifdiv
//File Name     :   float_mult.v
//Module name   :   float mult
//Full name     :   float number a times b and struct transform 
//
//Author        :   xiang tian
//Email         :   
//Data          :   2020/5/13
//Version       :   V1.01
//
//Abstract      :   
//                  
//Called  by    :   GPU
//
//Modification history
//-----------------------------------------------------
//1.00: intial version 
//1.01: add busy port
//
//-----------------------------------------------------------------------------

//-----------------------------
//DEFINE MACRO
//----------------------------- 
module float_mult(
    clk,
    rst_n,
    busy,
    en,
    exp_a,
    man_a,
    sign_a,
    iszero_a,
    isinf_a,
    isnan_a,  
    exp_newton,
    man_newton,
    sign_newton,
    iszero_newton,
    isinf_newton,
    isnan_newton,
    exp_mult,
    sign_mult,
    man_mult,
    iszero_mult,
    exception_mult,
    valid
);     

input             clk;
input             rst_n;
input             busy;
input             en;
input      [8:0]  exp_a;
input      [30:0] man_a;
input             sign_a;
input             iszero_a;
input             isinf_a;
input             isnan_a;   
input      [8:0]  exp_newton;
input      [24:0] man_newton;
input             sign_newton;
input             iszero_newton;
input             isinf_newton;
input             isnan_newton;
output reg [8:0]  exp_mult;
output reg        sign_mult;
output reg [30:0] man_mult;
output reg [2:0]  exception_mult;
output reg        iszero_mult;
output reg        valid;

wire        sign_o;
wire [32:0] mult_tmp;
wire [30:0] mult_rlt;
wire signed [9:0]  exp_o;
wire        isnan_o;
wire        div_by_0;
wire        overflow;
wire        underflow;

wire [57:0] a_time_rcp = {1'b1,man_a} * {1'b1,man_newton} ;   //1.31 * 1.25


assign div_by_0 = iszero_newton;
assign isnan_o = isnan_a | isnan_newton;
assign overflow  = ($signed(exp_o) > 127) ? 1'b1 : 1'b0;
assign underflow = ($signed(exp_o) < -(126+23)) ? 1'b1 : 1'b0;//including demormalized number

assign sign_o = sign_a ^ sign_newton;
assign mult_tmp = a_time_rcp[57:25];// + a_time_rcp[24];//a_time_rcp >>25;  //2.31

assign mult_rlt = (mult_tmp[32] ==1'b1) ? mult_tmp[31:1] : //mult_tmp -> (2,3)
                                          mult_tmp[30:0] ; //mult_tmo -> (1,2)

assign exp_o = {exp_a[8],exp_a} + {exp_newton[8],exp_newton} + mult_tmp[32];


always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)  iszero_mult <= 1'b0;
    else if(en && !busy) iszero_mult <= sign_a;
end           

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)  sign_mult <= 1'b0;
    else if(en && !busy) sign_mult <= sign_o;
end           

always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
    begin
        exp_mult <= 9'b0;
        man_mult <= 31'b0;
        exception_mult <= 3'b0;
        iszero_mult <= 1'b0;
    end        
    else if(en && !busy)
    begin
        casex({isnan_o,isinf_a,isinf_newton,div_by_0,overflow,underflow})
            6'b1x_xxxx: begin exception_mult <= 3'b011; exp_mult <= 9'h81;  man_mult <= 31'b0;         iszero_mult <= 1'b1;     end
            6'b01_xxxx: begin exception_mult <= 3'b100; exp_mult <= 9'd127; man_mult <= 31'h7fff_ffff; iszero_mult <= 1'b0;     end
            6'b00_1xxx: begin exception_mult <= 3'b100; exp_mult <= 9'h81;  man_mult <= 31'b0;         iszero_mult <= 1'b1;     end
            6'b00_01xx: begin exception_mult <= 3'b101; exp_mult <= 9'd127; man_mult <= 31'h7fff_ffff; iszero_mult <= 1'b0;     end
            6'b00_001x: begin exception_mult <= 3'b001; exp_mult <= 9'd127; man_mult <= 31'h7fff_ffff; iszero_mult <= 1'b0;     end
            6'b00_0001: begin exception_mult <= 3'b010; exp_mult <= 9'h81;  man_mult <= 31'b0;         iszero_mult <= 1'b1;     end
            default:    begin exception_mult <= 3'b0;   exp_mult <= exp_o;  man_mult <= mult_rlt;      iszero_mult <= iszero_a; end
        endcase
    end
end           


always @(posedge clk or negedge rst_n)
begin
    if(!rst_n) valid <= 1'b0;
    else if(!busy) valid <= en;
end         

endmodule
